package com.wolfeyes.framework.aspect;

import com.wolfeyes.common.annotation.SysDictInfo;
import com.wolfeyes.common.utils.translation.SysDictDO;
import com.wolfeyes.system.service.SysDictService;
import com.wolfeyes.common.utils.network.http.HttpContextUtils;
import com.wolfeyes.common.utils.network.ip.IpUtils;
import com.wolfeyes.common.utils.translation.SysDictUtils;
import com.wolfeyes.common.utils.network.webpage.PageUtils;

import org.aspectj.lang.JoinPoint;
import org.aspectj.lang.ProceedingJoinPoint;
import org.aspectj.lang.annotation.*;
import org.aspectj.lang.reflect.MethodSignature;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
//import sun.net.util.IPAddressUtil;

import javax.servlet.http.HttpServletRequest;
import java.lang.reflect.Method;
import java.util.Arrays;
import java.util.List;

/**
 * 
 * @description SysDict系统(字典 <<==>> 翻译)的转换处理切面类
 * @projectName bootdo
 * @className SysDictAspect.java
 * @author yanyl
 * @email 1991yanyl@163.com
 * @date 2018-09-28 15:53:58
 * @since 2017年02月02日下午5:37:39
 * @createTime 2018年06月09日 下午17:04:13
 * @version 1.0.0
 * @return String
 * @throws Exception
 */

@Aspect
//此处注解不能少
@Component
public class SysDictAspect {

	/**
	 * slf4j日志对象
	 */
    private static final Logger logger = LoggerFactory.getLogger(SysDictAspect.class);

	@Autowired
	private SysDictService sysDictService;
	
    /**
     * 参考常见问题FAQ文档：配置多个aop:pointcut
     * @description AOP事务切入点
     * @projectName bootdo
     * @className WebLogAspect.java
     * @methodName doSysDictPointCut()
     * @author yanyl
     * @email 1991yanyl@163.com
     * @date 2018-07-04 15:53:58
     * @since 2017年07月09日下午5:37:39
     * @createTime 2018年07月09日 下午17:04:13
     * @version 1.0.0
     * @return String
     * @throws Exception
     */
	// 两个..代表所有（当前包和）子目录，最后括号里的两个..代表所有（任何）参数
    @Pointcut("(execution( * com.wolfeyes.web.controller..*.*(..))) && (@annotation(com.wolfeyes.common.annotation.SysDictInfo))")
    public void doSysDictPointCut() {
    	
    	// 开始切入
    	logger.info("Spring Framework AOP 事务aspectjweaver-V1.8.13开始切入#SysDictAspect");
    }


    /*
    @Before("doSysDictPointCut()")
    public void doBefore(JoinPoint joinPoint) throws Throwable {
    	
        // 接收到请求，记录请求内容
    	HttpServletRequest request = HttpContextUtils.getHttpServletRequest();
    	
        // 记录下请求内容
        logger.info("请求地址 : " + request.getRequestURL().toString());
        logger.info("HTTP METHOD : " + request.getMethod());
        //获取客户端IP地址，如果通过代理进来，则透过防火墙获取真实IP地址
        String ip = IPUtils.getIpAddr(request);
        // 获取请求主机真实的ip地址
        logger.info("客户端IP : " + ip);
        logger.info("CLASS_METHOD : " + joinPoint.getSignature().getDeclaringTypeName() + "."
                + joinPoint.getSignature().getName());
        logger.info("参数 : " + Arrays.toString(joinPoint.getArgs()));
//        loggger.info("参数 : " + joinPoint.getArgs());

    }
    */

    @AfterReturning(pointcut = "doSysDictPointCut()", returning = "result") // returning的值和doAfterReturning的参数名一致
    public void doAfterReturning(JoinPoint joinPoint, Object result) throws Throwable {
    	
    	// 判断返回类型
    	if(result instanceof PageUtils) {
    		
    		// 目标对象
    		Object targetObject = joinPoint.getTarget();
    		// 方法的参数
    		Object[] args = joinPoint.getArgs();
    		// args.length
    		int length = args.length;
    		// 获取方法参数的字节码
    		Class<?>[] argsClazz = new Class[length];
			for(int index = 0; index < length; index++) {
    			// java.util.LinkHashMap.class --> java.util.Map.class
    			// 或获取简称args[index].getClass().getSimpleName()
    			if(args[index].getClass().getName().contains("Map")) {
    				argsClazz[index] = args[index].getClass().getInterfaces()[0];
				} else {
					argsClazz[index] = args[index].getClass();
    			}
    		}
    		// 此处涉及Java反射机制--获取泛型类的字节码
    		Class<? extends Object> controllerClazz = joinPoint.getSignature().getDeclaringType();
    		// 切入的controller类名
    		String className = joinPoint.getSignature().getDeclaringTypeName();
    		// 切入的controller里具体方法名
    		String methodName = joinPoint.getSignature().getName();
    		// getDeclaredMethod获取泛型类的某个固定方法 参数为 方法名 参数列表
    		Method method = controllerClazz.getDeclaredMethod(methodName, argsClazz);
    		
    		// 获取注解@SysDictInfo
    		SysDictInfo sysDictInfo = method.getAnnotation(SysDictInfo.class);
    		if (sysDictInfo != null && sysDictInfo.type() > 0 && sysDictInfo.value().length > 0) {
    			// 存在待翻译的字典类型编码
                // 待翻译的属性数组
                String[] propertiesArr = sysDictInfo.properties();
                // 字典类型编码数组
                String[] valueArr = sysDictInfo.value();
                // 操作类型，是否触发翻译
                int type = sysDictInfo.type();
                // 操作模块
                String model = sysDictInfo.model();
                // valueArr.length
                length = valueArr.length;
                
        		// 翻译开始
        		logger.debug("获取注解@SysDictInfo成功");
        		logger.info(sysDictInfo.toString());
        		
                // 开始遍历翻译
				for(int index = 0; index < length; index++) {
            		// 泛型列表
            		List<SysDictDO> tList = this.sysDictService.listByType(valueArr[index]);
        			PageUtils pageUtils = (PageUtils) result;
            		List<?> dataList = pageUtils.getRows();
            		for(Object object : dataList) {
            			// 属性元素-快速解码（字典-->翻译）
            			SysDictUtils.decode(object, propertiesArr[index], null, tList);
            		}
                }
    		}
    		
    		/*
    		// 商户名称
    		List<DictDO> merchantNameList = this.dictService.listByType("spjt_shmc");
    		
    		// 交易类型
    		List<DictDO> transactionTypeList = this.dictService.listByType("spjt_jylx");
    		
    		// 交易方式（银行卡类型或快捷支付方式）
    		List<DictDO> transactionWayList = this.dictService.listByType("spjt_jyfs");
    		
			PageUtils pageUtils = (PageUtils) result;
    		List<?> tList = pageUtils.getRows();
    		for(Object object : tList) {
    			
    			// 商户名称-快速解码（字典-->翻译）
    			SysDictUtils.decode(object, "MerchantName", null, merchantNameList);
    			
    			// 交易类型-快速解码（字典-->翻译）
    			SysDictUtils.decode(object, "TransactionType", null, transactionTypeList);
    			
    			// 交易方式（银行卡类型或快捷支付方式）-快速解码（字典-->翻译）
    			SysDictUtils.decode(object, "TransactionWay", null, transactionWayList);
    			
    		}
    		*/
    		
    		// 翻译结束
    		logger.debug("字典系统快速解码（翻译）成功");
    	}
    	
        // 处理完请求，返回内容(返回值太复杂时，打印的是物理存储空间的地址)
        logger.debug("返回值 : " + result);
    }

    @Around("doSysDictPointCut()")
    public Object doAround(ProceedingJoinPoint proceedingJoinPoint) throws Throwable {
    	
    	System.out.println("SysDictAspect aspect start");
    	
    	Object[] args = proceedingJoinPoint.getArgs();
    	logger.info("参数 : " + Arrays.toString(args));
    	/*
    	List<Object> args = Arrays.asList(args);
    	for (Object arg : args) {
    		System.out.println("arg is : " + arg);
    		
    	}
    	*/
    	
        long startTime = System.currentTimeMillis();
        
        // object 为方法的返回值
        Object object = proceedingJoinPoint.proceed();
        
        long endTime = System.currentTimeMillis();
        
		// 耗时：单位（秒）
		//System.out.println("用时 : " + (endTime - startTime) / 1000d + "秒");
        //logger.info("耗时 : " + (endTime - startTime) + " ms");
        logger.info("用时 : " + (endTime - startTime) / 1000d + "秒");
        
        System.out.println("SysDictAspect aspect end");
        
        return object;
    }
}
